package gin_util

import (
	"log"
	"strings"

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"

	app_global "app/app_src/framework/app/global"
	app_util "app/app_src/framework/app/util"
	app_constants "app/app_src/framework/constant/app"
	db_util "app/app_src/framework/db/util"
	gin_handler "app/app_src/framework/gin/handler"
	"app/app_src/framework/gin/util/embed_folder"
	template_wrapper "app/app_src/framework/template/wrapper"
	file_util "app/app_src/framework/util/file"
	web_util "app/app_src/framework/util/web"
	context_path_util "app/app_src/framework/util/web/context_path"
)

// 运行应用
func RunApp(engine *gin.Engine, defaultPort string) {
	// 获取启动参数
	args := app_util.GetArgs()
	env := args.Env
	configPath := args.Config
	// 获取配置参数
	config := app_util.GetConfig(configPath)
	// 初始工具类
	_InitUtil(args, config)

	if env == app_constants.ENV_LOCAL {
		appDir := app_global.AppDir()
		adjustedPath := file_util.JoinPath(appDir, _UtilContext.WebPublicDir)
		// 本地环境从本地文件系统读取静态资源
		staticFileSystem := static.LocalFile(adjustedPath, true)
		staticHandlerFunc := static.Serve(context_path_util.WithContextPath("/"), staticFileSystem)
		// 注册处理静态资源的路由
		engine.Use(staticHandlerFunc)
	} else {
		embedFS := app_global.EmbedFS()
		// 非本地环境从嵌入式文件系统读取静态资源
		staticFileSystem := embed_folder.EmbedFolder(*embedFS, _UtilContext.WebPublicDir)
		staticHandlerFunc := static.Serve(context_path_util.WithContextPath("/"), staticFileSystem)
		// 注册处理静态资源的路由
		engine.Use(staticHandlerFunc)
	}

	if !_UtilContext.UnitTestMode {
		// 监听端口
		_ListenPort(engine, config, defaultPort)
	}
}

// 获取 Gin 路由器
func GetEngine() *gin.Engine {
	if !_UtilContext.UnitTestMode {
		args := app_util.GetArgs()
		var env string = args.Env

		if env == app_constants.ENV_PROD {
			gin.SetMode(gin.ReleaseMode)
		}
	} else {
		gin.SetMode(gin.TestMode)
	}

	engine := gin.Default()
	// 添加错误处理器
	engine.NoRoute(gin_handler.NotFoundHandler)
	engine.Use(gin_handler.ServerErrorHandler)
	// 用于清理 current_scope 的脏数据
	engine.Use(gin_handler.CurrentScopeHandler)
	// 决定当前语言的处理器
	engine.Use(gin_handler.CurrentLanguageHandler)
	// 添加 session 支持
	store := cookie.NewStore([]byte(_UtilContext.CookieSecret))
	options := sessions.Options{
		Path:     context_path_util.WithContextPath("/"),
		Secure:   false,
		HttpOnly: true,
	}
	store.Options(options)
	engine.Use(sessions.Sessions(_UtilContext.SessionName, store))

	return engine
}

// 初始工具类
func _InitUtil(args *app_util.Args, config *app_util.Config) {
	env := args.Env

	// 初始 web_util
	//

	// HTML 模板配置
	htmlTemplateConfig := template_wrapper.NewTemplateConfig(template_wrapper.TEMPLATE_TYPE_HTML,
		_UtilContext.HtmlTemplatePrefix, _UtilContext.HtmlTemplateSuffix)
	htmlTemplateConfig.LeftDelim = _UtilContext.TemplateLeftDelim
	htmlTemplateConfig.RightDelim = _UtilContext.TemplateRightDelim
	// 脚本模板配置
	scriptTemplateConfig := template_wrapper.NewTemplateConfig(template_wrapper.TEMPLATE_TYPE_TEXT,
		_UtilContext.ScriptTemplatePrefix, _UtilContext.ScriptTemplateSuffix)
	scriptTemplateConfig.LeftDelim = _UtilContext.TemplateLeftDelim
	scriptTemplateConfig.RightDelim = _UtilContext.TemplateRightDelim
	// web_util 工具类上下文
	webUtilContext := web_util.NewUtilContext(htmlTemplateConfig, scriptTemplateConfig)

	if env == app_constants.ENV_PROD {
		htmlTemplateConfig.UseEmbedFS = true
		htmlTemplateConfig.CacheEnabled = true
		scriptTemplateConfig.UseEmbedFS = true
		scriptTemplateConfig.CacheEnabled = true
		webUtilContext.HtmlCacheEnabled = true
		webUtilContext.ScriptCacheEnabled = true
	}

	web_util.InitUtilContext(webUtilContext)

	// 初始 db_util
	//
	dbUtilContext := db_util.NewUtilContext(config.DataSource)
	db_util.InitUtilContext(dbUtilContext)
}

// 规范服务地址字符串
func _NormAddr(port string) string {
	if strings.Contains(port, ":") {
		return port
	} else {
		return ":" + port
	}
}

// 监听端口
func _ListenPort(router *gin.Engine, config *app_util.Config, defaultPort string) {
	if config != nil {
		httpAddr := _NormAddr(config.HttpPort)
		certFile := config.CertFile
		certKeyFile := config.CertKeyFile

		log.Println("Listening and serving on " + httpAddr)
		// 启动服务
		if certFile != "" || certKeyFile != "" {
			router.RunTLS(httpAddr, certFile, certKeyFile)
		} else {
			router.Run(httpAddr)
		}
	} else {
		httpAddr := _NormAddr(defaultPort)

		log.Println("Listening and serving on " + httpAddr)
		// 启动服务
		router.Run(httpAddr)
	}
}
